/*
 * $Id: QEEntryData.m 248 2008-09-08 15:31:38Z jon $
 * Sleeper
 *
 * Created by Jon Gordon on 2/8/08
 * Copyright Jon Gordon.  All rights reserved.
 * 
 * Permission is hereby granted, free of charge, to any person obtaining 
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including 
 * without limitation the rights to use, copy, modify, merge, publish, 
 * distribute, sublicense, and/or sell copies of the Software, and to 
 * permit persons to whom the Software is furnished to do so, subject to 
 * the following conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */


#import "QEEntryData.h"

#import "SleeperErrors.h"

#import "QEArrlData.h"
#import "QECallsign.h"

// power levels (in watts) relevant to November Sweepstakes
static const float MAX_LEGAL_POWER = 1500.0;
static const float MAX_LOW_POWER = 150.0;
static const float MAX_QRP_POWER = 5.0;


@interface QEEntryData (private)
- (id)extension;					// reserved for future expansion
- (void)setExtension:(id)newValue;
@end


@implementation QEEntryData
#pragma mark INITIALIZERS
+ (void)initialize
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    static BOOL initialized = NO;
    if (!initialized) {
        initialized = YES;
        [self setKeys:[NSArray arrayWithObject:@"category"]
triggerChangeNotificationsForDependentKey:@"multiOp"];
    } // if
} // initialize


- (id)init
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    return [self initWithName:nil 
			  entrantCallsign:nil 
                     address1:nil 
                     address2:nil 
                         city:nil 
              stateOrProvince:nil 
					 postCode:nil 
                      country:@"United States"
						email:nil
				entryCallsign:nil
				  outputPower:nil
					clubEntry:[NSNumber numberWithBool:NO]
					 clubName:nil
                      section:nil 
                     category:nil
                     assisted:[NSNumber numberWithBool:NO]
                     modeName:nil
                        check:nil
		  additionalOperators:[[[NSArray alloc] init] autorelease]
			   rigDescription:nil
		   antennaDescription:nil
				  soapboxText:nil];
} //init


- (id)initWithName:(NSString *)newName
   entrantCallsign:(NSString *)newEntrantCallsign
          address1:(NSString *)newAddress1
          address2:(NSString *)newAddress2
              city:(NSString *)newCity
   stateOrProvince:(NSString *)newStateOrProvince
		  postCode:(NSString *)newPostCode
           country:(NSString *)newCountry
			 email:(NSString *)newEmail
	 entryCallsign:(NSString *)newEntryCallsign
	   outputPower:(NSNumber *)newOutputPower
		 clubEntry:(NSNumber *)newClubEntry
		  clubName:(NSString *)newClubName
		   section:(NSString *)newSection
		  category:(NSString *)newCategory
          assisted:(NSNumber *)newAssisted
          modeName:(NSString *)newModeName
             check:(NSNumber *)newCheck
additionalOperators:(NSArray *)newAdditionalOperators
	rigDescription:(NSString *)newRigDescription
antennaDescription:(NSString *)newAntennaDescription
	   soapboxText:(NSString *)newSoapboxText
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    self = [super init];
    if (nil != self) {
        [self setName:newName];
        [self setEntrantCallsign:newEntrantCallsign];
        [self setAddress1:newAddress1];
        [self setAddress2:newAddress2];
        [self setCity:newCity];
        [self setStateProv:newStateOrProvince];
        [self setPostCode:newPostCode];
        [self setCountry:newCountry];
		[self setEmail:newEmail];
		[self setEntryCallsign:newEntryCallsign];
		[self setOutputPower:newOutputPower];
		[self setClubEntry:newClubEntry];
		[self setClubName:newClubName];
        [self setSection:newSection];
        [self setCategory:newCategory];
        [self setAssisted:newAssisted];
        [self setModeName:newModeName];
        [self setCheck:newCheck];
        [self setAdditionalOperators:newAdditionalOperators];
		[self setRigDescription:newRigDescription];
		[self setAntennaDescription:newAntennaDescription];
		[self setSoapboxText:newSoapboxText];
        
        [self setExtension:nil];
    } // if
    
    return self;
} // initWithName:entrantCallsign:address1:address2:city:stateOrProvince:postal:country:email:entryCallsign:outputPower:clubEntry:clubName:section:category:assisted:check:additionalOperators:rigDescription:antennaDescription:soapboxText

// Supports Cocoa's serialize/deserialize function
- (id)initWithCoder:(NSCoder *)coder {
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    self = [self init];
    
    [self setName:[coder decodeObjectForKey:@"EDName"]];
    [self setEntrantCallsign:[coder decodeObjectForKey:@"EDEntrantCallsign"]];
    [self setAddress1:[coder decodeObjectForKey:@"EDAddress1"]];
    [self setAddress2:[coder decodeObjectForKey:@"EDAddress2"]];
    [self setCity:[coder decodeObjectForKey:@"EDCity"]];
    [self setStateProv:[coder decodeObjectForKey:@"EDStateOrProvince"]];
    [self setPostCode:[coder decodeObjectForKey:@"EDPostCode"]];
    [self setCountry:[coder decodeObjectForKey:@"EDCountry"]];
	[self setEmail:[coder decodeObjectForKey:@"EDEmail"]];
	[self setEntryCallsign:[coder decodeObjectForKey:@"EDEntryCallsign"]];
	[self setOutputPower:[coder decodeObjectForKey:@"EDOutputPower"]];
	[self setClubEntry:[coder decodeObjectForKey:@"EDClubEntry"]];
	[self setClubName:[coder decodeObjectForKey:@"EDClubName"]];
    [self setSection:[coder decodeObjectForKey:@"EDSection"]];
    [self setCategory:[coder decodeObjectForKey:@"EDCategory"]];
    [self setAssisted:[coder decodeObjectForKey:@"EDAssisted"]];
    [self setModeName:[coder decodeObjectForKey:@"EDModeName"]];
    [self setCheck:[coder decodeObjectForKey:@"EDCheck"]];
    [self setAdditionalOperators:[coder decodeObjectForKey:@"EDAdditionalOperators"]];
	[self setRigDescription:[coder decodeObjectForKey:@"EDRigDescription"]];
	[self setAntennaDescription:[coder decodeObjectForKey:@"EDAntennaDescription"]];
	[self setSoapboxText:[coder decodeObjectForKey:@"EDSoapboxText"]];
	[self setExtension:[coder decodeObjectForKey:@"EDExtension01"]];
    
    return self;
} // initWithCoder:

// Supports Cocoa's serialize/deserialize function
- (void)encodeWithCoder:(NSCoder *)coder {
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    
    [coder encodeObject:[self name] forKey:@"EDName"];
    [coder encodeObject:[self entrantCallsign] forKey:@"EDEntrantCallsign"];
    [coder encodeObject:[self address1] forKey:@"EDAddress1"];
    [coder encodeObject:[self address2] forKey:@"EDAddress2"];
    [coder encodeObject:[self city] forKey:@"EDCity"];
    [coder encodeObject:[self stateProv] forKey:@"EDStateOrProvince"];
    [coder encodeObject:[self postCode] forKey:@"EDPostCode"];
    [coder encodeObject:[self country] forKey:@"EDCountry"];
	[coder encodeObject:[self email] forKey:@"EDEmail"];
	[coder encodeObject:[self entryCallsign] forKey:@"EDEntryCallsign"];
	[coder encodeObject:[self outputPower] forKey:@"EDOutputPower"];
	[coder encodeObject:[self clubEntry] forKey:@"EDClubEntry"];
	[coder encodeObject:[self clubName] forKey:@"EDClubName"];
    
    [coder encodeObject:[self section] forKey:@"EDSection"];
    [coder encodeObject:[self category] forKey:@"EDCategory"];
    
    [coder encodeObject:[self assisted] forKey:@"EDAssisted"];
    [coder encodeObject:[self modeName] forKey:@"EDModeName"];
    [coder encodeObject:[self check] forKey:@"EDCheck"];
    [coder encodeObject:[self additionalOperators] forKey:@"EDAdditionalOperators"];
	[coder encodeObject:[self rigDescription] forKey:@"EDRigDescription"];
	[coder encodeObject:[self antennaDescription] forKey:@"EDAntennaDescription"];
	[coder encodeObject:[self soapboxText] forKey:@"EDSoapboxText"];
	
	[coder encodeObject:[self extension] forKey:@"EDExtension01"];
} // encodeWithCoder:


#pragma mark VALIDATION METHODS
- (BOOL)validateEntryCategory:(NSError **)error
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    NSString *chosenCategory = [self category];
    if (nil == chosenCategory) {
        return YES;
    } // if
    
    BOOL result = NO;
    
    if ([@"S" isEqual:chosenCategory]) {
        // school clubs are unlimited for power, assistance, and # of ops
        result = YES;
    } else if ([@"M" isEqual:chosenCategory]) {
        // multiop station must list all operators
        if ((nil == [self additionalOperators]) || 
            (0 == [[self additionalOperators] count])) {
            if (nil != error) {
                NSMutableDictionary *userInfo = [[[NSMutableDictionary alloc] init] autorelease];
                [userInfo setObject:@"Missing Information" forKey:NSLocalizedDescriptionKey];
                [userInfo setObject:@"A multi-operator entry must list all operators."
                             forKey:NSLocalizedFailureReasonErrorKey];
                [userInfo setObject:@"List the additional operators under \"Additional Operators\" or pick a single-operator entry category." 
                             forKey:NSLocalizedRecoverySuggestionErrorKey];
                [userInfo setObject:[NSArray arrayWithObjects:@"Go Back", @"OK", nil]
                             forKey:NSLocalizedRecoveryOptionsErrorKey];
                *error = [[[NSError alloc] initWithDomain:QESleeperErrorDomain
                                                     code:QEMissingOutgoingData
                                                 userInfo:userInfo] autorelease];
            } // if
        } else {
            result = YES;
        } // else
    } else if ([@"U" isEqual:chosenCategory]) {
        // unlimited station: only restriction is single operator
        if ((nil == [self additionalOperators]) ||
            (0 == [[self additionalOperators] count])) {
            result = YES;
        } else if (nil != error) {
            NSMutableDictionary *userInfo = [[[NSMutableDictionary alloc] init] autorelease];
            [userInfo setObject:@"Inconsistent Entry Information" forKey:NSLocalizedDescriptionKey];
            [userInfo setObject:@"Multiple operators listed for single-op category."
                         forKey:NSLocalizedFailureReasonErrorKey];
            [userInfo setObject:@"Delete the additional operators or change the category to multioperator." 
                         forKey:NSLocalizedRecoverySuggestionErrorKey];
            [userInfo setObject:[NSArray arrayWithObjects:@"Go Back", @"OK", nil]
                         forKey:NSLocalizedRecoveryOptionsErrorKey];
            *error = [[[NSError alloc] initWithDomain:QESleeperErrorDomain
                                                 code:QEMissingOutgoingData
                                             userInfo:userInfo] autorelease];
        } // else if
    } else if ([@"B" isEqual:chosenCategory]) {
        // single-op high power: unassisted, more than 150 watts output
        if (((nil == [self additionalOperators]) ||
             (0 == [[self additionalOperators] count])) && 
            ![[self assisted] boolValue])  {
            result = YES;
        } else if (nil != error) {
            NSMutableString *recoveryTips = [[[NSMutableString alloc] init] autorelease];
            int errorCount = 0;
            if (!((nil == [self additionalOperators]) ||
                  (0 == [[self additionalOperators] count]))) {
                ++errorCount;
                [recoveryTips appendString:@"Delete the additional operators"];
            } // if
            if ([[self assisted] boolValue]) {
                ++errorCount;
                if (1 == errorCount) {
                    [recoveryTips appendString:@"Uncheck the \"assisted\" box"];
                } else {
                    [recoveryTips appendString:@" and uncheck the \"assisted\" box"];
                } // else
            } // if
            [recoveryTips appendString:@"."];
            
            NSMutableDictionary *userInfo = [[[NSMutableDictionary alloc] init] autorelease];
            [userInfo setObject:@"Inconsistent Entry Information" forKey:NSLocalizedDescriptionKey];
            [userInfo setObject:@"The entered information is inconsistent with the selected category."
                         forKey:NSLocalizedFailureReasonErrorKey];
            [userInfo setObject:recoveryTips
                         forKey:NSLocalizedRecoverySuggestionErrorKey];
            [userInfo setObject:[NSArray arrayWithObjects:@"Go Back", @"OK", nil]
                         forKey:NSLocalizedRecoveryOptionsErrorKey];
            *error = [[[NSError alloc] initWithDomain:QESleeperErrorDomain
                                                 code:QEMissingOutgoingData
                                             userInfo:userInfo] autorelease];
        } // else if        
    } else if ([@"A" isEqual:chosenCategory]) {
        // single-op low power: unassisted, more than 5 watts, but less than
        // or equal to 150 watts
        if (((nil == [self additionalOperators]) ||
             (0 == [[self additionalOperators] count])) && 
            ![[self assisted] boolValue] &&
            ([[self outputPower] floatValue] <= MAX_LOW_POWER))  {
            result = YES;
        } else if (nil != error) {
            NSMutableString *recoveryTips = [[[NSMutableString alloc] init] autorelease];
            int errorCount = 0;
            if (!((nil == [self additionalOperators]) ||
                  (0 == [[self additionalOperators] count]))) {
                ++errorCount;
                [recoveryTips appendString:@"Delete the additional operators"];
            } // if
            if ([[self assisted] boolValue]) {
                ++errorCount;
                if (1 == errorCount) {
                    [recoveryTips appendString:@"Uncheck the \"assisted\" box"];
                } else {
                    [recoveryTips appendString:@"; uncheck the \"assisted\" box"];
                } // else
            } // if
            if ([[self outputPower] floatValue] > MAX_LOW_POWER) {
                ++errorCount;
                if (1 == errorCount) {
                    [recoveryTips appendString:@"Correct the power level or select a different category"];
                } else {
                    [recoveryTips appendString:@"; correct the power level or select a different category"];
                } // else
            } // if
            
            if (2 == errorCount) {
                [recoveryTips replaceCharactersInRange:[recoveryTips rangeOfString:@";"] withString:@" and"];
            } else if (3 == errorCount) {
                NSRange lastSemicolon = [recoveryTips rangeOfString:@";" options:NSBackwardsSearch];
                [recoveryTips insertString:@" and" atIndex:(lastSemicolon.location + 1)];
            } // else if
            
            [recoveryTips appendString:@"."];
            
            NSMutableDictionary *userInfo = [[[NSMutableDictionary alloc] init] autorelease];
            [userInfo setObject:@"Inconsistent Entry Information" forKey:NSLocalizedDescriptionKey];
            [userInfo setObject:@"The entered information is inconsistent with the selected category."
                         forKey:NSLocalizedFailureReasonErrorKey];
            [userInfo setObject:recoveryTips
                         forKey:NSLocalizedRecoverySuggestionErrorKey];
            [userInfo setObject:[NSArray arrayWithObjects:@"Go Back", @"OK", nil]
                         forKey:NSLocalizedRecoveryOptionsErrorKey];
            *error = [[[NSError alloc] initWithDomain:QESleeperErrorDomain
                                                 code:QEMissingOutgoingData
                                             userInfo:userInfo] autorelease];
        } // else if        
    } else if ([@"Q" isEqual:chosenCategory]) {
        // single-op QRP: unassisted, 5 watts or less
        if (((nil == [self additionalOperators]) ||
             (0 == [[self additionalOperators] count])) && 
            ![[self assisted] boolValue] &&
            ([[self outputPower] floatValue] <= MAX_QRP_POWER))  {
            result = YES;
        } else if (nil != error) {
            NSMutableString *recoveryTips = [[[NSMutableString alloc] init] autorelease];
            int errorCount = 0;
            if (!((nil == [self additionalOperators]) ||
                  (0 == [[self additionalOperators] count]))) {
                ++errorCount;
                [recoveryTips appendString:@"Delete the additional operators"];
            } // if
            if ([[self assisted] boolValue]) {
                ++errorCount;
                if (1 == errorCount) {
                    [recoveryTips appendString:@"Uncheck the \"assisted\" box"];
                } else {
                    [recoveryTips appendString:@"; uncheck the \"assisted\" box"];
                } // else
            } // if
            if ([[self outputPower] floatValue] > MAX_QRP_POWER) {
                ++errorCount;
                if (1 == errorCount) {
                    [recoveryTips appendString:@"Correct the power level or select a different category"];
                } else {
                    [recoveryTips appendString:@"; correct the power level or select a different category"];
                } // else
            } // if
            
            if (2 == errorCount) {
                [recoveryTips replaceCharactersInRange:[recoveryTips rangeOfString:@";"] withString:@" and"];
            } else if (3 == errorCount) {
                NSRange lastSemicolon = [recoveryTips rangeOfString:@";" options:NSBackwardsSearch];
                [recoveryTips insertString:@" and" atIndex:(lastSemicolon.location + 1)];
            } // else if
            
            [recoveryTips appendString:@"."];
            
            NSMutableDictionary *userInfo = [[[NSMutableDictionary alloc] init] autorelease];
            [userInfo setObject:@"Inconsistent Entry Information" forKey:NSLocalizedDescriptionKey];
            [userInfo setObject:@"The entered information is inconsistent with the selected category."
                         forKey:NSLocalizedFailureReasonErrorKey];
            [userInfo setObject:recoveryTips
                         forKey:NSLocalizedRecoverySuggestionErrorKey];
            [userInfo setObject:[NSArray arrayWithObjects:@"Go Back", @"OK", nil]
                         forKey:NSLocalizedRecoveryOptionsErrorKey];
            *error = [[[NSError alloc] initWithDomain:QESleeperErrorDomain
                                                 code:QEMissingOutgoingData
                                             userInfo:userInfo] autorelease];
        } // else if        
    } else {
        // CAN'T HAPPEN
        NSAssert(false, @"CAN'T HAPPEN: Unrecognized category for entry");
    }     // else 
    return result;
} // validateEntryCategory:


#pragma mark PUBLIC ACCESSORS
-(NSString *)name
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    return [[name retain] autorelease];
} // name

-(void)setName:(NSString *)newValue
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    if (name != newValue) {
        id tmp = name;
        name = [newValue copy];
        [tmp release];
    } // if
} // setName:


-(NSString *)entrantCallsign
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    return [[entrantCallsign retain] autorelease];
} // entrantCallsign

-(void)setEntrantCallsign:(NSString *)newValue
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    if (entrantCallsign != newValue) {
        id tmp = entrantCallsign;
        entrantCallsign = [newValue copy];
        [tmp release];
    } // if
    
    // if we haven't yet set a callsign for the *entry*, copy
    // this one as a default
    NSString *oldEntryCallsign = [self entryCallsign];
    if ((nil == oldEntryCallsign) || (0 == [oldEntryCallsign length])) {
        NSString *newEntryCallsign = [[newValue copy] autorelease];
        if ([self validateEntryCallsign:(&newEntryCallsign) error:nil]) {
            [self setEntryCallsign:newEntryCallsign];
        } // if
    } // if
} // setEntrantCallsign:

- (BOOL)validateEntrantCallsign:(id *)ioValue error:(NSError **)outError
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    return [QECallsign isValidBaseCallsign:ioValue error:outError];
} // validateEntrantCallsign:error:



-(NSString *)address1
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    return [[address1 retain] autorelease];
} // address1

-(void)setAddress1:(NSString *)newValue
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    if (address1 != newValue) {
        id tmp = address1;
        address1 = [newValue copy];
        [tmp release];
    } // if
} // setAddress1:


-(NSString *)address2
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    return [[address2 retain] autorelease];
} // address2

-(void)setAddress2:(NSString *)newValue
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    if (address2 != newValue) {
        id tmp = address2;
        address2 = [newValue copy];
        [tmp release];
    } // if
} // setAddress2:


-(NSString *)city
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    return [[city retain] autorelease];
} // city

-(void)setCity:(NSString *)newValue
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    if (city != newValue) {
        id tmp = city;
        city = [newValue copy];
        [tmp release];
    } // if
} // setCity:


-(NSString *)stateProv
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    return [[stateProv retain] autorelease];
} // stateOrProvince

-(void)setStateProv:(NSString *)newValue
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    if (stateProv != newValue) {
        id tmp = stateProv;
        stateProv = [newValue copy];
        [tmp release];
    } // if
} // setStateProv:


- (NSString *)postCode
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    return [[postCode retain] autorelease];
} // postCode

- (void)setPostCode:(NSString *)newValue
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    if (postCode != newValue) {
        id tmp = postCode;
        postCode = [newValue copy];
        [tmp release];
    } // if
} // setPostCode:


-(NSString *)country
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    return [[country retain] autorelease];
} // country

-(void)setCountry:(NSString *)newValue
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    if (country != newValue) {
        id tmp = country;
        country = [newValue copy];
        [tmp release];
    } // if
} // setCountry:


- (NSString *)email
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
	return [[email retain] autorelease];
} // email

- (void)setEmail:(NSString *)newValue
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
	if (email != newValue) {
        id tmp = email;
		email = [newValue copy];
        [tmp release];
	} // if
} // setEmail:


- (NSString *)entryCallsign
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
	return [[entryCallsign retain] autorelease];
} // entryCallsign

- (void)setEntryCallsign:(NSString *)newValue
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
	if (entryCallsign != newValue) {
        id tmp = entryCallsign;
		entryCallsign = [newValue copy];;
        [tmp release];
	} // if
} // setEntryCallsign:

- (BOOL)validateEntryCallsign:(id *)ioValue error:(NSError **)outError
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    return [QECallsign isValidBaseCallsign:ioValue error:outError];
} // validateEntryCallsign:error:


- (NSNumber *)outputPower
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
	return [[outputPower retain] autorelease];
} // outputPower

- (void)setOutputPower:(NSNumber *)newValue
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
	if (outputPower != newValue) {
        id tmp = outputPower;
		outputPower = [newValue copy];;
        [tmp release];
	} // if
} // setOutputPower:

- (BOOL)validateOutputPower:(id *)ioValue error:(NSError **)outError
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    BOOL result = NO;
    
    if (nil == *ioValue) {
        result = YES;
    } else if ((0.0 < [*ioValue floatValue]) && ([*ioValue floatValue] <= MAX_LEGAL_POWER)) {
        result = YES;
    } else if (nil != outError) {
        int errorCode = QEPowerInvalidValue;
        NSString *description = [NSString stringWithFormat:@"%@ is not a valid level for output power.",
                                 *ioValue];
        NSArray *objArray = [NSArray arrayWithObjects:description, nil];
        NSArray *keyArray = [NSArray arrayWithObjects:NSLocalizedDescriptionKey, nil];
        NSDictionary *eDict = [NSDictionary dictionaryWithObjects:objArray forKeys:keyArray];
        *outError = [[[NSError alloc] initWithDomain:QESleeperErrorDomain code:errorCode userInfo:eDict] autorelease];
    } // else if
    
    return result;
} // validateOutputPower:error:


- (NSNumber *)clubEntry
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    return [[clubEntry retain] autorelease];
} // clubEntry

- (void)setClubEntry:(NSNumber *)newValue
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    if (clubEntry != newValue) {
        id tmp = clubEntry;
        clubEntry = [newValue copy];
        [tmp release];
    } // if
} // setClubEntry:


- (NSString *)clubName
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    return [[clubName retain] autorelease];
} // clubName

- (void)setClubName:(NSString *)newValue
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    if (clubName != newValue) {
        id tmp = clubName;
        clubName = [newValue copy];
        [tmp release];
    } // if
} // setClubName:


-(NSString *)section
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    return [[section retain] autorelease];
} // section

-(void)setSection:(NSString *)newValue
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    if (section != newValue) {
        id tmp = section;
        section = [newValue copy];
        [tmp release];
    } // if
} // setSection:

- (BOOL)validateSection:(id *)ioValue error:(NSError **)outError
{
    BOOL result = NO;
    NSString *src = *ioValue;
    
    if (nil == src) {
        result = YES;
    } else {
        src = [src uppercaseString];
        if ([QEArrlData isSectionAbbr:src]) {
            result = YES;
            *ioValue = src;
        } else {
            int errorCode = QESectionInvalidValue;
            NSString *description = [NSString stringWithFormat:@"\"%@\" is not recognized as a section abbreviation.",
                                     *ioValue];
            NSArray *objArray = [NSArray arrayWithObjects:description, nil];
            NSArray *keyArray = [NSArray arrayWithObjects:NSLocalizedDescriptionKey, nil];
            NSDictionary *eDict = [NSDictionary dictionaryWithObjects:objArray forKeys:keyArray];
            *outError = [[[NSError alloc] initWithDomain:QESleeperErrorDomain code:errorCode userInfo:eDict] autorelease];
        }
    } // else
    
    return result;
} // validateSection:error:


-(NSString *)category
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    return [[category retain] autorelease];
}  // category

-(void)setCategory:(NSString *)newValue
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    if (category != newValue) {
        id tmp = category;
        category = [newValue copy];
        [tmp release];
    } // if
} // setCategory:

- (BOOL)validateCategory:(id *)ioValue error:(NSError **)outError
{
    BOOL result = NO;
    NSString *src = *ioValue;
    
    if (nil == src) {
        result = YES;
    } else {
        src = [src uppercaseString];
        if ([QEArrlData isCategoryDesignation:src]) {
            result = YES;
            *ioValue = src;
        } else {
            int errorCode = QECategoryInvalidValue;
            NSString *description = [NSString stringWithFormat:@"\"%@\" is not recognized as a category code.",
                                     *ioValue];
            NSArray *objArray = [NSArray arrayWithObjects:description, nil];
            NSArray *keyArray = [NSArray arrayWithObjects:NSLocalizedDescriptionKey, nil];
            NSDictionary *eDict = [NSDictionary dictionaryWithObjects:objArray forKeys:keyArray];
            *outError = [[[NSError alloc] initWithDomain:QESleeperErrorDomain code:errorCode userInfo:eDict] autorelease];
        } // else
    } // else
    
    return result;
} // validateCategory:error:


- (NSNumber *)multiOp
{
    return [NSNumber numberWithBool:((nil != [self category]) &&
                                     ([@"S" isEqual:[self category]] ||
                                      [@"M" isEqual:[self category]]))];
} // multiOp


- (NSNumber *)assisted
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    return [[assisted retain] autorelease];
} // asissted

- (void)setAssisted:(NSNumber *)newValue
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    if (assisted != newValue) {
        id tmp = assisted;
        assisted = [newValue copy];
        [tmp release];
    } // if
} // setAssisted:


- (NSString *)modeName
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    return [[modeName retain] autorelease];
} // modeName

- (void)setModeName:(NSString *)newValue
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    if (modeName != newValue) {
        id tmp = modeName;
        modeName = [newValue copy];
        [tmp release];
    } // if
} // setModeName:


- (NSNumber *)check
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    return [[check retain] autorelease];
} // check

-(void)setCheck:(NSNumber *)newValue
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    if (check != newValue) {
        id tmp = check;
        check = [newValue copy];
        [tmp release];
    } // if
} // setCheck:


- (NSArray *)additionalOperators
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    return [[additionalOperators retain] autorelease];
} // additionalOperators

- (void)setAdditionalOperators:(NSArray *)newValue
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    if (additionalOperators != newValue) {
        id tmp = additionalOperators;
        additionalOperators = [[NSArray arrayWithArray:newValue] retain];
        [tmp release];
    } // if
} // setAdditionalOperators:


- (NSString *)rigDescription
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    return [[rigDescription retain] autorelease];
} // rigDescription

- (void)setRigDescription:(NSString *)newValue
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    if (newValue != rigDescription) {
        id tmp = rigDescription;
        rigDescription = [newValue copy];
        [tmp release];
    } // if
} // setRigDescription:


- (NSString *)antennaDescription
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    return [[antennaDescription retain] autorelease];
} // antennaDescription

- (void)setAntennaDescription:(NSString *)newValue
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    if (newValue != antennaDescription) {
        id tmp = antennaDescription;
        antennaDescription = [newValue copy];
        [tmp release];
    } // if
} // setAntennaDescription:


- (NSString *)soapboxText
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    return [[soapboxText retain] autorelease];
} // soapboxText

- (void)setSoapboxText:(NSString *)newValue
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    if (newValue != soapboxText) {
        id tmp = soapboxText;
        soapboxText = [newValue copy];
        [tmp release];
    } // if
} // setSoapboxText:


#pragma mark HOUSEKEEPING METHODS
-(void)dealloc
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    [self setName:nil];
    [self setEntrantCallsign:nil];
    [self setAddress1:nil];
    [self setAddress2:nil];
    [self setCity:nil];
    [self setStateProv:nil];
    [self setPostCode:nil];
    [self setCountry:nil];
    [self setEmail:nil];
    [self setEntryCallsign:nil];
    [self setOutputPower:nil];
    [self setClubEntry:nil];
    [self setClubName:nil];
    [self setSection:nil];
    [self setCategory:nil];
    [self setAssisted:nil];
    [self setModeName:nil];
    [self setCheck:nil];
    [self setAdditionalOperators:nil];
    [self setRigDescription:nil];
    [self setAntennaDescription:nil];
    [self setSoapboxText:nil];
    
    [self setExtension:nil];
    
    [super dealloc];
} // dealloc

- (id)copyWithZone:(NSZone *)zone
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    QEEntryData *newData = [[[self class] allocWithZone:zone]
                            initWithName:[self name] 
                            entrantCallsign:[self entrantCallsign] 
                            address1:[self address1] 
                            address2:[self address2] 
                            city:[self city] 
                            stateOrProvince:[self stateProv] 
                            postCode:[self postCode] 
                            country:[self country]
                            email:[self email]
                            entryCallsign:[self entryCallsign]
                            outputPower:[self outputPower]
                            clubEntry:[self clubEntry]
                            clubName:[self clubName]
                            section:[self section] 
                            category:[self category] 
                            assisted:[self assisted]
                            modeName:[self modeName]
                            check:[self check]
                            additionalOperators:[self additionalOperators]
                            rigDescription:[self rigDescription]
                            antennaDescription:[self antennaDescription]
                            soapboxText:[self soapboxText]];
    return newData;
} // copyWithZone:

- (unsigned int)hash
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    static const unsigned int HASH_BASE = 17;
    static const unsigned int HASH_FACTOR = 37;
    
    unsigned int result = HASH_BASE;
    result = (result * HASH_FACTOR) + [[self name] hash];
    result = (result * HASH_FACTOR) + [[self entrantCallsign] hash];
    result = (result * HASH_FACTOR) + [[self address1] hash];
    result = (result * HASH_FACTOR) + [[self address2] hash];
    result = (result * HASH_FACTOR) + [[self city] hash];
    result = (result * HASH_FACTOR) + [[self stateProv] hash];
    result = (result * HASH_FACTOR) + [[self postCode] hash];
    result = (result * HASH_FACTOR) + [[self country] hash];
	result = (result * HASH_FACTOR) + [[self email] hash];
	result = (result * HASH_FACTOR) + [[self entryCallsign] hash];
	result = (result * HASH_FACTOR) + [[self outputPower] hash];
	result = (result * HASH_FACTOR) + [[self clubEntry] hash];
	result = (result * HASH_FACTOR) + [[self clubName] hash];
    result = (result * HASH_FACTOR) + [[self section] hash];
    result = (result * HASH_FACTOR) + [[self category] hash];
    result = (result * HASH_FACTOR) + [[self assisted] hash];
    result = (result * HASH_FACTOR) + [[self modeName] hash];
    result = (result * HASH_FACTOR) + [[self check] intValue];
    result = (result * HASH_FACTOR) + [[self additionalOperators] hash];
	result = (result * HASH_FACTOR) + [[self rigDescription] hash];
	result = (result * HASH_FACTOR) + [[self antennaDescription] hash];
	result = (result * HASH_FACTOR) + [[self soapboxText] hash];
    
    return result;
} // hash

- (BOOL)isEqual:(id)anObject
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
    return (anObject == self) ||
    ([[self name] isEqual:[anObject name]] &&
    [[self entrantCallsign] isEqual:[anObject entrantCallsign]] &&
    [[self address1] isEqual:[anObject address1]] &&
    [[self address2] isEqual:[anObject address2]] &&
    [[self city] isEqual:[anObject city]] &&
    [[self stateProv] isEqual:[anObject stateProv]] &&
    [[self postCode] isEqual:[anObject postCode]] &&
    [[self country] isEqual:[anObject country]] &&
    [[self email] isEqual:[anObject email]] &&
    [[self entryCallsign] isEqual:[anObject entryCallsign]] &&
    [[self outputPower] isEqual:[anObject outputPower]] &&
    [[self clubEntry] isEqual:[anObject clubEntry]] &&
    [[self clubName] isEqual:[anObject clubName]] &&
    [[self section] isEqual:[anObject section]] &&
    [[self category] isEqual:[anObject category]] &&
    [[self assisted] isEqual:[anObject assisted]] &&
    [[self modeName] isEqual:[anObject modeName]] &&
    [[self check] isEqual:[anObject check]] &&
    [[self additionalOperators] isEqual:[anObject additionalOperators]] &&
    [[self rigDescription] isEqual:[anObject rigDescription]] &&
    [[self antennaDescription] isEqual:[anObject antennaDescription]] &&
    [[self soapboxText] isEqual:[anObject soapboxText]]);
} // isEqual:
@end

@implementation QEEntryData (private)
- (id)extension
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
	return [[extension retain] autorelease];
} // extension

- (void)setExtension:(id)newExtension
{
    NSLog(@"MESSAGE: %s", __PRETTY_FUNCTION__);
	if (extension != newExtension) {
		[extension autorelease];
		extension = [newExtension copy];
	} // if
} // setExtension:
@end
